﻿#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

//文件的打开和关闭
//FILE* fopen (const char* filename, const char* mode);
//                         文件名               打开方式
//int fclose (FILE* stream);

// 一、文件的顺序读写 了解8个函数

//1.字符输出函数 - 输出一个字符
//int fputc ( int character, FILE* stream);
//int main()
//{
//	//打开文件
//	FILE* pf = fopen("data.txt", "w");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件
//	/*fputc('a', pf);
//	fputc('b', pf);
//	fputc('c', pf);
//	fputc('d', pf);*/
//	for (int i = 0; i < 26; i++) {
//		fputc('a' + i, pf);
//		fputc('\n', pf);
//	}
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//2.字符输⼊函数 - 得到一个字符
//int fgetc (FILE* stream)
//int main()
//{
//	//打开文件
//	FILE* pf = fopen("data1.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	for (int i = 0; i < 9; i++) {
//		int ch = fgetc(pf);
//		printf("%c ", ch);
//	}
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//3.⽂本⾏输出函数 - 输出一行字符
//int fputs(const char* str,FILE* stream);
//int main()
//{
//	//打开文件
//	FILE* pf = fopen("data.txt", "w");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	fputs("asdfgh\n", pf);
//	fputs("asd322\n", pf);
//	fputs("ca72dfgh\n", pf);
//	fputs("asdfaca\n", pf);
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//4.⽂本⾏输⼊函数 - 输入一行字符
//char* fgets(char* str, int num ,FILE* stream);
//int main()
//{
//	//打开文件
//	FILE* pf = fopen("data1.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	char arr[] = "xxxxxxxxxxxxxxxxxxxx";
//	fgets(arr, 13, pf);
//	fputs(arr, stdout);
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//5.格式化输出函数
//int fprintf (FILE* stream,const* format,...);
//struct Stu
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	struct Stu s = { "zhangpeng",22,95.5f };
//	FILE* pf = fopen("data.txt", "w");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件
//	fprintf(pf, "%s %d %.2f", s.name, s.age, s.score);
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//6.格式化输入函数
//int fscanf (FILE* stream,const* format,...);
//struct Stu
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	struct Stu s = { 0 };
//	FILE* pf = fopen("data1.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件
//	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
//	fprintf(stdout, "%s %d %.2f\n", s.name, s.age, s.score);
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//7.⼆进制输出
//size_t fwrite (const void * str, size_t size, size_t count,FILE* stream);
//struct Stu
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	struct Stu s = { "zhangpeng", 22, 95.5f };
//	FILE* pf = fopen("data.txt", "wb");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//二进制的形式写文件
//	fwrite(&s, sizeof(s), 1, pf);
//
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//8.⼆进制输入
//size_t fread (void * str, size_t size, size_t count,FILE* stream);
//struct Stu
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	struct Stu s = { 0 };
//	FILE* pf = fopen("data1.txt", "rb");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//二进制的形式读文件
//	fread(&s, sizeof(s), 1, pf);
//	printf("%s %d %.2f\n", s.name, s.age, s.score);
//
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


// 二、文件的随机读写
// 1.fseek
//根据⽂件指针的位置和偏移量来定位⽂件指针
//int fseek ( FILE * stream, long int offset, int origin );
//  int origin  分三类： 1.SEEK_SET  2.SEEK_CUR  3.SEEK_END
//int main()
//{
//	FILE* pf = fopen("data1.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	int ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	//fseek(pf, 0, SEEK_SET);
//	//fseek(pf, -3, SEEK_CUR);
//	fseek(pf, -8, SEEK_END);
//	ch = fgetc(pf);//a
//	printf("%c\n", ch);
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

// 2.ftell
//返回⽂件指针相对于起始位置的偏移量
//long int ftell ( FILE * stream );
//int main()
//{
//	FILE* pf = fopen("data1.txt", "r");//内容：abcdefgh
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	int ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	ch = fgetc(pf);//c
//	printf("%c\n", ch);
//
//	int n = ftell(pf);//c的位置  3
//	printf("%d\n", n);
//
//	//也可以算某一段字符串的个数
//	fseek(pf, -1, SEEK_END);//相当于最后一位字符（h）
//	ch = fgetc(pf);
//	printf("%c\n", ch);//h
//
//	n = ftell(pf);
//	printf("%d\n", n);//8
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

// 3.rewind
//让⽂件指针的位置回到⽂件的起始位置
//void rewind ( FILE * stream );
//int main()
//{
//	FILE* pf = fopen("data1.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	int ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	rewind(pf);//让⽂件指针的位置回到⽂件的起始位置
//	ch = fgetc(pf);
//	printf("%c\n", ch);//a
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//写一个代码，完成将data.txt文件的内容，拷贝一份生成data_copy.txt文件
//从data.txt中读取数据
//写到data_copy.txt的文件中
//int main()
//{
//	FILE* pfread = fopen("data.txt", "r");
//	if (pfread == NULL)
//	{
//		perror("fopen->data.txt");
//		return 1;
//	}
//	FILE* pfwrite = fopen("data_copy.txt", "w");
//	if (pfwrite == NULL)
//	{
//		fclose(pfread);
//		pfread = NULL;
//		perror("fopen->data1.txt");
//		return 1;
//	}
//	//数据的读写（拷贝）
//	int ch = 0;
//	while ((ch = fgetc(pfread)) != EOF)
//	{
//		fputc(ch, pfwrite);
//	}
//
//	fclose(pfread);
//	pfread = NULL;
//	fclose(pfwrite);
//	pfwrite = NULL;
//
//	return 0;
//}


//技巧
//int main()
//{
//	//打开文件，为了写
//	//如果文件打来失败，会返回NULL
//	//
//	//FILE* pf = fopen("C:\\Users\\zpeng\\Desktop\\data.txt", "w");
//	//. 表示当前目录
//	//.. 表示上一级路径
//	//FILE* pf = fopen("./../../data.txt", "w");
//	FILE* pf = fopen("data.txt", "w");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件
//
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//了解使用sscanf()和sprintf()函数
// int sscanf( const char* s, const char* format, ...);
// 从一个字符串中读取一个格式化的数据
// int sprintf( const char* s, const char* format, ...);
//把一个格式化的数据转化成字符串
//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	struct S s = { "zhangpeng",22,88.5f };
//	struct S t = { 0 };
//	char arr[100] = { 0 };
//
//	sprintf(arr, "%s %d %.2f", s.name, s.age, s.score);
//	printf("%s\n", arr);
//
//	sscanf(arr, "%s %d %f", t.name, &(t.age), &(t.score));
//	printf("%s %d %.2f", t.name, t.age, t.score);
//
//	return 0;
//}


#include <stdlib.h>
//文件读取结束的判断
//feof 的作⽤是：当⽂件读取结束的时候，判断是读取结束的原因是否是：遇到⽂件尾结束
//ferror 的作⽤是：当⽂件读取结束的时候，判断是读取结束的原因是否是：遇到错误
 
//1.文本文件的例子
//读取文本判断是否结束时，fgetc看返回值是否为EOF, fgets看返回值是否为NULL

//int main(void)
//{
//	int c; // 注意：int，⾮char，要求处理EOF
//	FILE* fp = fopen("data1.txt", "r");
//	if (fp == NULL) {
//		perror("File opening failed");
//		return EXIT_FAILURE;
//	}
//	//fgetc 当读取失败的时候或者遇到⽂件结束的时候，都会返回EOF
//	while ((c = fgetc(fp)) != EOF) // 标准C I/O读取⽂件循环
//	{
//		putchar(c);
//	}
//	//判断是什么原因结束的
//	if (ferror(fp))
//		puts("I/O error when reading");
//	else if (feof(fp))
//		puts("End of file reached successfully");
//
//	fclose(fp);
//	fp = NULL;
//
//	return 0;
//}

//2.二进制文件的例子
//二进制文件判断读取结束，看实际读取个数是否小于要求读取个数

enum { SIZE = 5 };
int main(void)
{
	double a[SIZE] = { 1.,2.,3.,4.,5. };
	FILE* fp = fopen("data.txt", "wb"); // 必须⽤⼆进制模式
	fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组
	fclose(fp);

	double b[SIZE];
	fp = fopen("data.txt", "rb");
	size_t ret_code = fread(b, sizeof(*b), SIZE, fp); // 读 double 的数组
	if (ret_code == SIZE) {
		puts("Array read successfully, contents: ");
		for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
		putchar('\n');
	}
	else { // error handling
		if (feof(fp))
			printf("Error reading data.txt : unexpected end of file\n");
		else if (ferror(fp)) {
			perror("Error reading data.txt");
		}
	}
	fclose(fp);
}